import time
from datetime import datetime
import hashlib
from tablestore import *
from tablestore.retry import WriteRetryPolicy

OTS_DEPLOY_CONFIG_BETA = 'beta'
OTS_DEPLOY_CONFIG_PREV = 'prev'
OTS_DEPLOY_CONFIG_PROD = 'prod'

ACCOUNT_TYPE_SUPER_USER = 0
ACCOUNT_TYPE_STAFF_USER = 1
ACCOUNT_TYPE_CLIENT_USER = 2

GID_BETA_OFFSET = 0
GID_PREV_OFFSET = 100
GID_PROD_OFFSET = 200

CATEGORY_AD_AREA = 0
CATEGORY_ARTICLE = 1
CATEGORY_TUTOR = 2
CATEGORY_TUTOR_MATCH = 3

OPENID_TYPE_STAFF = 0
OPENID_TYPE_CLIENT = 1

ots_client = OTSClient('https://straight.cn-shenzhen.ots.aliyuncs.com'
                       , 'LTAI5peLQQ5dQ9gi'
                       , 'neDmHQjhIexyRMAk4cBusOxK5iLFDe'
                       , 'straight'
                       , logger_name='table_store.log'
                       , retry_policy=WriteRetryPolicy())


def create_configs():
    schema_of_primary_key = [('name', 'STRING')]
    table_meta = TableMeta('Configs', schema_of_primary_key)
    table_options = TableOptions()
    reserved_throughput = ReservedThroughput(CapacityUnit(0, 0))
    try:
        ots_client.create_table(table_meta, table_options, reserved_throughput)
        print('create table succeeded, waiting for partition load')
        time.sleep(60)
    except OTSServiceError as e:
        print(e.get_error_message())
        if e.get_error_code() != 'OTSObjectAlreadyExist':
            exit(-1)


def create_staffs():
    # 创建主键列的schema，包括PK的个数，名称和类型
    # 第一个PK列为整数，名称是pk0，这个同时也是分片列
    # 第二个PK列为整数，名称是pk1。其他可选的类型包括STRING，BINARY，这里使用INTEGER。
    schema_of_primary_key = [
        ('account', 'STRING'),
        ('uid', 'INTEGER', PK_AUTO_INCR)
    ]

    # 通过表名和主键列的schema创建一个tableMeta
    table_meta = TableMeta('Staffs', schema_of_primary_key)

    # 创建TableOptions，数据保留31536000秒，超过后自动删除；最大3个版本；写入时指定的版本值和当前标准时间相差不能超过1天。
    table_options = TableOptions(-1, 1, 86400)

    # 设定预留读吞吐量为0，预留写吞吐量为0
    reserved_throughput = ReservedThroughput(CapacityUnit(0, 0))

    # 调用client的create_table接口，如果没有抛出异常，则说明成功，否则失败
    try:
        ots_client.create_table(table_meta, table_options, reserved_throughput)
        print('create table succeeded, waiting for partition load')
        # 当创建了一个表之后，通常要等待1分钟时间使partition load完成，才能进行各种操作。
        time.sleep(60)
    except OTSServiceError as e:
        print(e.get_error_message())
        if e.get_error_code() != 'OTSObjectAlreadyExist':
            exit(-1)


def create_categories():
    schema_of_primary_key = [('gid', 'INTEGER'), ('cid', 'INTEGER', PK_AUTO_INCR)]
    table_meta = TableMeta('Categories', schema_of_primary_key)
    table_options = TableOptions()
    reserved_throughput = ReservedThroughput(CapacityUnit(0, 0))
    try:
        ots_client.create_table(table_meta, table_options, reserved_throughput)
        print('create table succeeded, waiting for partition load')
        time.sleep(60)
    except OTSServiceError as e:
        print(e.get_error_message())
        if e.get_error_code() != 'OTSObjectAlreadyExist':
            exit(-1)


def create_advertisement():
    schema_of_primary_key = [('category_id', 'INTEGER'), ('aid', 'INTEGER', PK_AUTO_INCR)]
    table_meta = TableMeta('Advertisement', schema_of_primary_key)
    table_options = TableOptions()
    reserved_throughput = ReservedThroughput(CapacityUnit(0, 0))
    try:
        ots_client.create_table(table_meta, table_options, reserved_throughput)
        print('create table succeeded, waiting for partition load')
        time.sleep(60)
    except OTSServiceError as e:
        print(e.get_error_message())
        if e.get_error_code() != 'OTSObjectAlreadyExist':
            exit(-1)


def create_articles():
    schema_of_primary_key = [('category_id', 'INTEGER'), ('aid', 'INTEGER', PK_AUTO_INCR)]
    table_meta = TableMeta('Articles', schema_of_primary_key)
    table_options = TableOptions()
    reserved_throughput = ReservedThroughput(CapacityUnit(0, 0))
    try:
        ots_client.create_table(table_meta, table_options, reserved_throughput)
        print('create table succeeded, waiting for partition load')
        time.sleep(60)
    except OTSServiceError as e:
        print(e.get_error_message())
        if e.get_error_code() != 'OTSObjectAlreadyExist':
            exit(-1)


def create_tutors():
    schema_of_primary_key = [('category_id', 'INTEGER'), ('tid', 'INTEGER', PK_AUTO_INCR)]
    table_meta = TableMeta('Tutors', schema_of_primary_key)
    table_options = TableOptions()
    reserved_throughput = ReservedThroughput(CapacityUnit(0, 0))
    try:
        ots_client.create_table(table_meta, table_options, reserved_throughput)
        print('create table succeeded, waiting for partition load')
        time.sleep(60)
    except OTSServiceError as e:
        print(e.get_error_message())
        if e.get_error_code() != 'OTSObjectAlreadyExist':
            exit(-1)


def create_tutor_matches():
    schema_of_primary_key = [('create_time', 'INTEGER'), ('category_id', 'INTEGER'), ('mid', 'INTEGER', PK_AUTO_INCR)]
    table_meta = TableMeta('TutorMatches', schema_of_primary_key)
    table_options = TableOptions()
    reserved_throughput = ReservedThroughput(CapacityUnit(0, 0))
    try:
        ots_client.create_table(table_meta, table_options, reserved_throughput)
        print('create table succeeded, waiting for partition load')
        time.sleep(60)
    except OTSServiceError as e:
        print(e.get_error_message())
        if e.get_error_code() != 'OTSObjectAlreadyExist':
            exit(-1)


def create_clients():
    schema_of_primary_key = [('account', 'STRING'), ('uid', 'INTEGER', PK_AUTO_INCR)]
    table_meta = TableMeta('Clients', schema_of_primary_key)
    table_options = TableOptions()
    reserved_throughput = ReservedThroughput(CapacityUnit(0, 0))
    try:
        ots_client.create_table(table_meta, table_options, reserved_throughput)
        print('create table succeeded, waiting for partition load')
        time.sleep(60)
    except OTSServiceError as e:
        print(e.get_error_message())
        if e.get_error_code() != 'OTSObjectAlreadyExist':
            exit(-1)


def create_third_client_binding():
    schema_of_primary_key = [('openid', 'STRING')]
    table_meta = TableMeta('ThirdClient', schema_of_primary_key)
    table_options = TableOptions()
    reserved_throughput = ReservedThroughput(CapacityUnit(0, 0))
    try:
        ots_client.create_table(table_meta, table_options, reserved_throughput)
        print('create table succeeded, waiting for partition load')
        time.sleep(60)
    except OTSServiceError as e:
        print(e.get_error_message())
        if e.get_error_code() != 'OTSObjectAlreadyExist':
            exit(-1)


def create_subjects():
    schema_of_primary_key = [('key', 'STRING')]
    table_meta = TableMeta('Subjects', schema_of_primary_key)
    table_options = TableOptions()
    reserved_throughput = ReservedThroughput(CapacityUnit(0, 0))
    try:
        ots_client.create_table(table_meta, table_options, reserved_throughput)
        print('create table succeeded, waiting for partition load')
        time.sleep(60)
    except OTSServiceError as e:
        print(e.get_error_message())
        if e.get_error_code() != 'OTSObjectAlreadyExists':
            exit(-1)


def init_staffs():
    # 添加超级管理员
    # 主键的第一个主键列是gid，值是整数1，第二个主键列是uid，值是整数101。
    h = hashlib.md5()
    h.update(b'admin')
    password = h.hexdigest()
    columns_to_get = ['create_time', 'update_time']
    attribute_column_put = []

    inclusive_start_primary_key = [('account', 'admin'), ('uid', INF_MIN)]
    exclusive_end_primary_key = [('account', 'admin'), ('uid', INF_MAX)]
    limit = 1
    try:
        consumed, next_start_primary_key, row_list, next_token = ots_client.get_range(
            table_name='Staffs',
            direction=Direction.FORWARD,
            inclusive_start_primary_key=inclusive_start_primary_key,
            exclusive_end_primary_key=exclusive_end_primary_key,
            columns_to_get=columns_to_get,
            limit=limit,
            max_version=1
        )
        if len(row_list) == 0:
            create_time = int(datetime.now().timestamp())
            attribute_column_put.append(('create_time', create_time))
            attribute_column_put.append(('update_time', create_time))
            attribute_column_put.append(('password', password))
            primary_key = [
                ('account', 'admin'),
                ('uid', PK_AUTO_INCR)
            ]
            row = Row(primary_key, attribute_column_put)
            consumed, return_row = ots_client.put_row('Staffs', row, return_type=ReturnType.RT_PK)
        else:
            print(row_list[0].primary_key)
            print(row_list[0].attribute_columns)
            primary_key = row_list[0].primary_key
            attribute_column_put.append(('password', password))
            attribute_column_put.append(('update_time', int(datetime.now().timestamp())))
            attribute_columns = {
                'PUT': attribute_column_put
            }
            row = Row(primary_key, attribute_columns)
            condition = Condition(RowExistenceExpectation.IGNORE)
            consumed, return_row = ots_client.update_row('Staffs', row, condition)

        print('put row succeed, consume %s write cu.' % consumed.write)
    except OTSClientError as e:
        print('get row failed, http_status:%d, error_message:%s' % (e.get_http_status(), e.get_error_message()))
    except OTSServiceError as e:
        print('get row failed, http_status:%d, error_code:%s, error_message:%s, request_id:%s' % (e.get_http_status(),
                                                                                                  e.get_error_code(),
                                                                                                  e.get_error_message(),
                                                                                                  e.get_request_id()))


def init_categories():
    put_row_items = []
    timestamp = int(datetime.now().timestamp())
    for k, v in {
        CATEGORY_AD_AREA: [
            [
                ('key', 'App'),
                ('name', 'Carousel'),
                ('description', 'App 轮播图'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ], [
                ('key', 'App'),
                ('name', 'Middle Carousel'),
                ('description', 'App 页面中部轮播图'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ], [
                ('key', 'MiniProgram'),
                ('name', 'Carousel'),
                ('description', '小程序轮播图'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ], [
                ('key', 'MiniProgram'),
                ('name', 'Middle Carousel'),
                ('description', '小程序中部轮播图'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ], [
                ('key', 'MiniProgram'),
                ('name', 'Academic DNA Poster'),
                ('description', 'DNA 海报'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ]
        ],
        CATEGORY_TUTOR_MATCH: [
            [
                ('key', 'System'),
                ('name', 'Normal'),
                ('description', '普通匹配'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ],
            [
                ('key', 'System'),
                ('name', 'DNA'),
                ('description', 'DNA匹配'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ]
        ],
        CATEGORY_TUTOR: [
            [
                ('key', 'System'),
                ('name', 'Normal'),
                ('description', '导师团队'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ],
            [
                ('key', 'System'),
                ('name', 'Golden'),
                ('description', '金牌导师'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ]
        ],
        CATEGORY_ARTICLE: [
            [
                ('key', 'System'),
                ('name', 'Starter'),
                ('description', '新手专属'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ],
            [
                ('key', 'System'),
                ('name', 'Hot'),
                ('description', '热门文章'),
                ('create_time', timestamp),
                ('update_time', timestamp)
            ]
        ]
    }.items():
        primary_key = [('gid', k), ('cid', PK_AUTO_INCR)]
        for content in v:
            content_dict = dict(content)
            column_condition = CompositeColumnCondition(LogicalOperator.AND)
            column_condition.add_sub_condition(SingleColumnCondition('key',
                                                                     content_dict['key'],
                                                                     ComparatorType.EQUAL))
            column_condition.add_sub_condition(SingleColumnCondition('name',
                                                                     content_dict['name'],
                                                                     ComparatorType.EQUAL))
            inclusive_start_primary_key = [('gid', k), ('cid', INF_MIN)]
            exclusive_end_primary_key = [('gid', k), ('cid', INF_MAX)]
            consumed, \
            next_start_primary_key, \
            row_list, \
            next_token = ots_client.get_range('Categories',
                                              Direction.FORWARD,
                                              inclusive_start_primary_key,
                                              exclusive_end_primary_key,
                                              [],
                                              1,
                                              column_filter=column_condition,
                                              max_version=1)
            if len(row_list) != 0:
                primary_key_temp = row_list[0].primary_key
                primary_key[1] = primary_key_temp[1]
                print(primary_key)
                attribute_columns = {
                    'PUT': content
                }
            else:
                attribute_columns = content

            row = Row(primary_key, attribute_columns)
            condition = Condition(RowExistenceExpectation.IGNORE)

            if len(row_list) != 0:
                item = UpdateRowItem(row, condition)
            else:
                item = PutRowItem(row, condition)
            put_row_items.append(item)

    request = BatchWriteRowRequest()
    request.add(TableInBatchWriteRowItem('Categories', put_row_items))

    try:
        result = ots_client.batch_write_row(request)
        print('Result status: %s' % (result.is_all_succeed()))

        # check put
        print('check first table\'s put results:')
        succ, fail = result.get_put()
        for item in succ:
            print('Put succeed, consume %s write cu.' % item.consumed.write)
        for item in fail:
            print('Put failed, error code: %s, error message: %s' % (item.error_code, item.error_message))

        # check update
        print('check first table\'s update results:')
        succ, fail = result.get_update()
        for item in succ:
            print('Update succeed, consume %s write cu.' % item.consumed.write)
        for item in fail:
            print('Update failed, error code: %s, error message: %s' % (item.error_code, item.error_message))

        # check delete
        print('check first table\'s delete result:')
        succ, fail = result.get_delete()
        for item in succ:
            print('Delete succeed, consume %s write cu.' % item.consumed.write)
        for item in fail:
            print('Delete failed, error code: %s, error message: %s' % (item.error_code, item.error_message))

    except OTSClientError as e:
        print('get row failed, http_status: %d, error_message: %s' % (e.get_http_status(), e.get_error_message()))
    except OTSServiceError as e:
        print('get row failed, http_status: %d, error_code: %s, error_message: %s, request_id: %s'
              % (e.get_http_status(), e.get_error_code(), e.get_error_message(), e.get_request_id()))


def init_mini_carousel():
    try:
        now = int(time.time())
        put_row_items = []
        for i in range(0, 3):
            primary_key = [('category_id', 1521125581726992), ('aid', PK_AUTO_INCR)]
            attribute_columns = [
                ('title', '小程序轮播图'),
                ('create_time', str(now)),
                ('update_time', str(now)),
                ('link', ''),
                ('link_type', 'internal'),
                ('file_key', ''),
                ('sort', i)
            ]
            row = Row(primary_key, attribute_columns)
            condition = Condition(RowExistenceExpectation.IGNORE)
            item = PutRowItem(row, condition)
            put_row_items.append(item)

        request = BatchWriteRowRequest()
        request.add(TableInBatchWriteRowItem('Advertisement', put_row_items))
        result = ots_client.batch_write_row(request)
        # check put
        print('check first table\'s put results:')
        succ, fail = result.get_put()
        for item in succ:
            print('Put succeed, consume %s write cu.' % item.consumed.write)
        for item in fail:
            print('Put failed, error code: %s, error message: %s' % (item.error_code, item.error_message))
    except OTSClientError as e:
        print('get row failed, http_status: %d, error_message: %s' % (e.get_http_status(), e.get_error_message()))
    except OTSServiceError as e:
        print('get row failed, http_status: %d, error_code: %s, error_message: %s, request_id: %s'
              % (e.get_http_status(), e.get_error_code(), e.get_error_message(), e.get_request_id()))


def init_mini_middle_carousel():
    try:
        now = int(time.time())
        primary_key = [('category_id', 1521125581726993), ('aid', PK_AUTO_INCR)]
        attribute_columns = [
            ('title', '学术DNA检测轮播图'),
            ('create_time', str(now)),
            ('update_time', str(now)),
            ('link', ''),
            ('link_type', 'internal'),
            ('file_key', ''),
            ('sort', 0)
        ]
        row = Row(primary_key, attribute_columns)
        condition = Condition(RowExistenceExpectation.IGNORE)
        consumed, return_row = ots_client.put_row('Advertisement', row, condition)
        print('Write succeed, consume {0} write cu.'.format(consumed.write))
    except OTSClientError as e:
        print('get row failed, http_status: %d, error_message: %s' % (e.get_http_status(), e.get_error_message()))
    except OTSServiceError as e:
        print('get row failed, http_status: %d, error_code: %s, error_message: %s, request_id: %s'
              % (e.get_http_status(), e.get_error_code(), e.get_error_message(), e.get_request_id()))


def init_mini_academic_dna():
    try:
        now = int(time.time())
        put_row_items = []
        for i in range(0, 3):
            primary_key = [('category_id', 1521125581726994), ('aid', PK_AUTO_INCR)]
            attribute_columns = [
                ('title', '学术DNA检测海报1'),
                ('create_time', str(now)),
                ('update_time', str(now)),
                ('link', ''),
                ('link_type', 'internal'),
                ('file_key', ''),
                ('sort', i)
            ]
            row = Row(primary_key, attribute_columns)
            condition = Condition(RowExistenceExpectation.IGNORE)
            item = PutRowItem(row, condition)
            put_row_items.append(item)

        request = BatchWriteRowRequest()
        request.add(TableInBatchWriteRowItem('Advertisement', put_row_items))
        result = ots_client.batch_write_row(request)
        # check put
        print('check first table\'s put results:')
        succ, fail = result.get_put()
        for item in succ:
            print('Put succeed, consume %s write cu.' % item.consumed.write)
        for item in fail:
            print('Put failed, error code: %s, error message: %s' % (item.error_code, item.error_message))
    except OTSClientError as e:
        print('get row failed, http_status: %d, error_message: %s' % (e.get_http_status(), e.get_error_message()))
    except OTSServiceError as e:
        print('get row failed, http_status: %d, error_code: %s, error_message: %s, request_id: %s'
              % (e.get_http_status(), e.get_error_code(), e.get_error_message(), e.get_request_id()))


def init_tutors():
    put_row_items = []
    golden_tutors = [
        {
            'name': '莫少斌',
            'intro': '',
            'brief': ''
        },
        {
            'name': '种晓丽',
            'intro': '',
            'brief': ''
        }
    ]
    tutors = [
        {
            'name': '龚世民',
            'intro': '',
            'brief': ''
        },
        {
            'name': '吉洁',
            'intro': '',
            'brief': ''
        },
        {
            'name': '李春霞',
            'intro': '',
            'brief': ''
        },
        {
            'name': '李晓辉',
            'intro': '',
            'brief': ''
        },
        {
            'name': '袁文彬',
            'intro': '',
            'brief': ''
        },
        {
            'name': '叶文彬',
            'intro': '',
            'brief': ''
        }
    ]
    put_row_items = []

    def put_row_items_append(category_id, tutor_array):
        for tutor in tutor_array:
            primary_key = [('category_id', category_id), ('tid', PK_AUTO_INCR)]
            attribute_columns = []
            for tutor_item in tutor.items():
                attribute_columns.append(tutor_item)
            row = Row(primary_key, attribute_columns)
            condition = Condition(RowExistenceExpectation.IGNORE)
            update_row_item = PutRowItem(row, condition)
            put_row_items.append(update_row_item)

    put_row_items_append(1521125581726998, golden_tutors)
    put_row_items_append(1521125581726997, tutors)

    request = BatchWriteRowRequest()
    request.add(TableInBatchWriteRowItem('Tutors', put_row_items))
    result = ots_client.batch_write_row(request)

    print('Result status: {0}'.format(result.is_all_succeed()))
    print('check first table\'s put results:')
    succ, fail = result.get_put()
    for item in succ:
        print('Put succeed, consume {0} write cu.'.format(item.consumed.write))
    for item in fail:
        print('Put failed, error code: {0}, error message: {1}'.format(item.error_code, item.error_message))


def init_subjects():
    try:
        primary_key = [('key', 'Economics')]
        attribute_columns = [
            ('cover', 'add7fd4befa1be1219436064ecdf2eafbe46a94c.jpg'),
            ('title', '经济学'),
            ('intro', '经济学的发展曾经分为两大主要分支，微观经济学和宏观经济学。经济学起源于古代中国经济思想、希腊色诺芬与亚里士多德为代表的早期经济学，经过亚当·斯密、马克思、凯恩斯、中国经济学家等经济学家的发展，经济学逐步由政治经济学向科学经济学发展，经济学理论体系和实际应用不断完善。'),
            ('type', 'hot')
        ]
        row = Row(primary_key, attribute_columns)
        condition = Condition(RowExistenceExpectation.IGNORE)
        ots_client.put_row('Subjects', row, condition)
    except OTSServiceError as e:
        print(e.get_error_message())


if __name__ == '__main__':
    # create_configs()
    # create_staffs()
    # create_categories()
    # create_advertisement()
    # create_articles()
    # create_tutors()
    # create_tutor_matches()
    # create_clients()
    # create_third_client_binding()
    # init_staffs()
    # init_categories()
    # init_mini_carousel()
    # init_mini_middle_carousel()
    # init_mini_academic_dna()
    # init_tutors()
    # create_subjects()
    init_subjects()
